package com.mine.async.jobexe;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.mine.async.enums.JobStatusEnum;
import com.mine.async.enums.JobTypeEnum;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;

@Slf4j
public abstract class DownloadJobExecutor {

    public final static Map<String, Integer> RUNING_MAP = new ConcurrentHashMap<>();

    public abstract String createJob(Selector selector, PageQuery pageQuery);

    public abstract String createJob(Function<PageQuery, Page> function, PageQuery pageQuery);

    public abstract String createJobGitHub(Function<PageQuery, PageRespBase> function, PageQuery pageQuery);

    public abstract DownloadJobHandler getDownloadJobHandler();

    protected void executeJob(String jobNo, Function<PageQuery, PageRespDTO> function, PageQuery pageQuery) {
        RUNING_MAP.put(jobNo, JobStatusEnum.READY.getCode());
        long exeStart = System.currentTimeMillis(), totalCount = 0, totalPage = 0;
        boolean selectSuccess = true, eachResult = true, hasNext;
        String selectFailMsg = null;
        int pageNo = 1, selectNum = 0;
        pageQuery.setPageNo(pageNo);
        pageQuery.setPageSize(getDownloadJobHandler().getPageSize(pageQuery.getTypeCode()));
        getDownloadJobHandler().beforeSelect(jobNo, pageQuery.getPageSize());
        RUNING_MAP.put(jobNo, JobStatusEnum.RUNING.getCode());
        String fileName = StrUtil.format("{}-{}", JobTypeEnum.getNameByCode(pageQuery.getTypeCode()), jobNo);
        PageRespDTO pageRespDTO;
        do {
            try {
                long eachStart = System.currentTimeMillis();
                pageRespDTO = function.apply(pageQuery);
                if (ObjectUtil.isNotNull(pageRespDTO) && CollUtil.isNotEmpty(pageRespDTO.getRecords())) {
                    if (selectNum == 0) {
                        totalCount = pageRespDTO.getTotal();
                        totalPage = pageRespDTO.getPages();
                        selectNum++;
                    }
                    eachResult = getDownloadJobHandler().afterSelectEach(jobNo, fileName, pageRespDTO.getCurrent(), pageRespDTO.getSize(), pageRespDTO.getRecords(), totalCount, eachStart);
                    if (BooleanUtil.isTrue(eachResult)) {
                        pageNo++;
                        hasNext = pageNo <= totalPage;
                        pageQuery.setPageNo(pageNo);
                    } else {
                        break;
                    }
                } else {
                    break;
                }

            } catch (Exception e) {
                log.error("执行导出任务-查询数据异常：{}", e);
                selectSuccess = false;
                selectFailMsg = e.getMessage();
                break;
            }
        } while (hasNext);
        try {
            if (BooleanUtil.isFalse(eachResult)) {
                log.error("执行导出任务-导出失败[填充错误]");
                RUNING_MAP.put(jobNo, JobStatusEnum.EXCEPTION.getCode());

            } else if (BooleanUtil.isFalse(selectSuccess)) {
                log.error("执行导出任务-导出失败[查询错误]");
                getDownloadJobHandler().afterSelectFail(jobNo, exeStart, selectFailMsg);
                RUNING_MAP.put(jobNo, JobStatusEnum.EXCEPTION.getCode());

            } else {
                log.info("执行导出任务-导出成功");
                getDownloadJobHandler().afterSelectSuccess(jobNo, exeStart, totalCount);
                RUNING_MAP.put(jobNo, JobStatusEnum.ENDED.getCode());
            }
        } catch (Exception e) {
            log.error("DownloadJobExecutor.executeJob", e);
        } finally {
            RUNING_MAP.remove(jobNo);
        }
    }

}
